/**
  ******************************************************************************
  * @file    BSP_pwm.c
  * @author  Silan - MC Team
  * @version 1.0.0
  * @date    2017/07/19
  * @brief   PWM Related Config Source File
  * @details None
  * @note    None
  ******************************************************************************
  * @attention
  * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
  * AS A RESULT, SILAN MICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
  * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
  * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
  * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  ******************************************************************************
  * Change History
  * -# 2017/07/19 | v1.0.0 | Wangjianlong | Creat file.
  *
  ******************************************************************************
  */

/*******************************************************************************
 * Include file
 ******************************************************************************/
#include "system_SC32F58128.h"

#include "GlobalInclude.h"

#include "BSP_pwm.h"
#include "BSP_adc.h"
#include "DrvParamCommon.h"

/*******************************************************************************
 * Global data for the project
 ******************************************************************************/
struct PWMGEN g_sPfcPwm  = PWMGEN_DEFAULTS;
struct PWMGEN g_sPmsmPwm = PWMGEN_DEFAULTS;
struct PWMGEN g_sFanPwm  = PWMGEN_DEFAULTS;

/*******************************************************************************
 * Local data for the current file
 ******************************************************************************/

/*******************************************************************************
 * Local prototypes function
 ******************************************************************************/

/*******************************************************************************
 * Local function for the current file
 ******************************************************************************/

/*******************************************************************************
 * Global function for the project
 ******************************************************************************/

/**
  * @brief  PMSM PWM Initialization.
  */
void PmsmPwmInit(struct PWMGEN pwm)
{
  PWM_PMSM_CHNL0->TBPRD = pwm.PeriodMax;
  PWM_PMSM_CHNL1->TBPRD = pwm.PeriodMax;
  PWM_PMSM_CHNL2->TBPRD = pwm.PeriodMax;

  /* Init Timer-Base Control Register */
  PWM_PMSM_CHNL0->TBCTL = (TIMER_CNT_UP + CNTLD_ENABLE + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);
  PWM_PMSM_CHNL1->TBCTL = (TIMER_CNT_UP + CNTLD_ENABLE + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);
  PWM_PMSM_CHNL2->TBCTL = (TIMER_CNT_UP + CNTLD_ENABLE + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);

  /* Init Compare Control Register */
  PWM_PMSM_CHNL0->CMPCTL = (LOADAMODE_PRD + LOADBMODE_PRD);
  PWM_PMSM_CHNL1->CMPCTL = (LOADAMODE_PRD + LOADBMODE_PRD);
  PWM_PMSM_CHNL2->CMPCTL = (LOADAMODE_PRD + LOADBMODE_PRD);

  /* Init Action Qualifier Output A Register */
  PWM_PMSM_CHNL0->AQCTLA = (CAU_SET + CBU_CLEAR);
  PWM_PMSM_CHNL1->AQCTLA = (CAU_SET + CBU_CLEAR);
  PWM_PMSM_CHNL2->AQCTLA = (CAU_SET + CBU_CLEAR);
  PWM_PMSM_CHNL0->AQCTLB = (CAU_CLEAR + CBU_CLEAR);
  PWM_PMSM_CHNL1->AQCTLB = (CAU_CLEAR + CBU_CLEAR);
  PWM_PMSM_CHNL2->AQCTLB = (CAU_CLEAR + CBU_CLEAR);

  /* Init Dead-Band Generator Control Register for EPWM1-EPWM3 */
  PWM_PMSM_CHNL0->DBCTL = 0x33;// BP_DISABLE + POLSEL_ACTIVE_HI + PWMB_IN
  PWM_PMSM_CHNL1->DBCTL = 0x33;// BP_DISABLE + POLSEL_ACTIVE_HI + PWMB_IN
  PWM_PMSM_CHNL2->DBCTL = 0x33;// BP_DISABLE + POLSEL_ACTIVE_HI + PWMB_IN

  /* Init Dead-Band Generator for EPWM1-EPWM3 */
  PWM_PMSM_CHNL0->DBFED = pwm.Deadband;
  PWM_PMSM_CHNL1->DBFED = pwm.Deadband;
  PWM_PMSM_CHNL2->DBFED = pwm.Deadband;
  PWM_PMSM_CHNL0->DBRED = pwm.Deadband;
  PWM_PMSM_CHNL1->DBRED = pwm.Deadband;
  PWM_PMSM_CHNL2->DBRED = pwm.Deadband;

  /* Init Digital-Compare */
  ACCESS_ENABLE;
  PWM_PMSM_CHNL0->DCTRIPSEL_b.DCAHCOMPSEL = 10; ///< AH=CTRIP2, PMSM H/W FAULT
  PWM_PMSM_CHNL1->DCTRIPSEL_b.DCAHCOMPSEL = 10; ///< AH=CTRIP2, PMSM H/W FAULT
  PWM_PMSM_CHNL2->DCTRIPSEL_b.DCAHCOMPSEL = 10; ///< AH=CTRIP2, PMSM H/W FAULT
  PWM_PMSM_CHNL0->TZDCSEL_b.DCAEVT1 = 2;        ///< DCAH = high, DCAL = don't care
  PWM_PMSM_CHNL1->TZDCSEL_b.DCAEVT1 = 2;        ///< DCAH = high, DCAL = don't care
  PWM_PMSM_CHNL2->TZDCSEL_b.DCAEVT1 = 2;        ///< DCAH = high, DCAL = don't care
  PWM_PMSM_CHNL0->DCACTL_b.EVT1FRCSYNCSEL = 1;  ///< ASYNC
  PWM_PMSM_CHNL1->DCACTL_b.EVT1FRCSYNCSEL = 1;  ///< ASYNC
  PWM_PMSM_CHNL2->DCACTL_b.EVT1FRCSYNCSEL = 1;  ///< ASYNC
  ACCESS_DISABLE;

  /* Init Trip Zone */
  ACCESS_ENABLE;
  PWM_PMSM_CHNL0->TZSEL = ENABLE_DCAEVT1_OST + ENABLE_TZ5_OST + ENABLE_TZ4_OST;
  PWM_PMSM_CHNL1->TZSEL = ENABLE_DCAEVT1_OST + ENABLE_TZ5_OST + ENABLE_TZ4_OST;
  PWM_PMSM_CHNL2->TZSEL = ENABLE_DCAEVT1_OST + ENABLE_TZ5_OST + ENABLE_TZ4_OST;
  PWM_PMSM_CHNL0->TZCTL = (TZA_FORCE_LO + TZB_FORCE_LO + DCAEVT1_NOTHING);
  PWM_PMSM_CHNL1->TZCTL = (TZA_FORCE_LO + TZB_FORCE_LO + DCAEVT1_NOTHING);
  PWM_PMSM_CHNL2->TZCTL = (TZA_FORCE_LO + TZB_FORCE_LO + DCAEVT1_NOTHING);
  PWM_PMSM_CHNL0->TZCLR = 0xffff;
  PWM_PMSM_CHNL1->TZCLR = 0xffff;
  PWM_PMSM_CHNL2->TZCLR = 0xffff;
  ACCESS_DISABLE;

  /* Init SOC Trigger Registers */
  if(g_sPmsmDrvParam.u8SingleShuntEn){
    PWM_PMSM_CHNL0->ETSEL = (SOCASEL_CMPA_EQ_UC + SOCASEL_ENABLE); ///< Generate an SOCA pulse on TBCTR = CMPA
    PWM_PMSM_CHNL1->ETSEL = (SOCASEL_CMPA_EQ_UC + SOCASEL_ENABLE); ///< when the timer is incrementing
    PWM_PMSM_CHNL2->ETSEL = (SOCASEL_CMPA_EQ_UC + SOCASEL_ENABLE);
  }else{
    PWM_PMSM_CHNL0->ETSEL = (SOCASEL_PRD_EQ + SOCASEL_ENABLE);     ///< Generate an SOCA pulse on TBCTR = 0
    PWM_PMSM_CHNL1->ETSEL = (SOCASEL_PRD_EQ + SOCASEL_ENABLE);
    PWM_PMSM_CHNL2->ETSEL = (SOCASEL_PRD_EQ + SOCASEL_ENABLE);
  }

  PWM_PMSM_CHNL0->ETPS = SOCAPRD_ONE_EVENT;     ///< Generate an SOCA pulse on every event
  PWM_PMSM_CHNL1->ETPS = SOCAPRD_ONE_EVENT;     ///< Generate an SOCA pulse on every event
  PWM_PMSM_CHNL2->ETPS = SOCAPRD_ONE_EVENT;     ///< Generate an SOCA pulse on every event

  /* SOCB signal for temp sample */
  PWM_PMSM_CHNL0->ETSEL += (SOCBSEL_PRD_EQ + SOCBSEL_ENABLE);
  PWM_PMSM_CHNL0->ETPS  += SOCBPRD_THREE_EVENT;

  /* Init Interrupt Registers */
  PWM_PMSM_CHNL0->ETSEL_b.INTEN = 1;              ///< Enable PWM Interrupt
  PWM_PMSM_CHNL0->ETSEL_b.INTESEL = 2;            ///< Generate an Interrupt when TBCTR = TBPRD
  PWM_PMSM_CHNL0->ETPS_b.INTPRD = 1;              ///< Generate an interrupt on every event
}

/**
  * @brief  PFC PWM Initialization.
  */
void PfcPwmInit(struct PWMGEN pwm)
{
  PWM_PFC_CHNL->TBCTL = (TIMER_CNT_UPDN + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);

  PWM_PFC_CHNL->CMPCTL = LOADAMODE_PRD;   ///< Load CMPA when TBCTR = PRD

  PWM_PFC_CHNL->TBPRD = pwm.PeriodMax;
  PWM_PFC_CHNL->CMPA = 0;

  PWM_PFC_CHNL->AQCTLB = (CAU_CLEAR + CAD_SET);
  PWM_PFC_CHNL->DBCTL = 0;

  /* TZ config (Over Current Protect and Current Limit) */
  ACCESS_ENABLE;
  PWM_PFC_CHNL->TZSEL = (ENABLE_TZ1_OST + ENABLE_TZ2_CBC + ENABLE_TZ5_OST + ENABLE_TZ4_OST);
  PWM_PFC_CHNL->TZCTL = TZB_FORCE_LO;
  ACCESS_DISABLE;

  /* PWM DCBEVT2 CONFIG (DC Voltage Limit)*/
  ACCESS_ENABLE;
  PWM_PFC_CHNL->DCTRIPSEL_b.DCBLCOMPSEL = 8;   ///< PWM CTRIP0, voltage limit signal
  PWM_PFC_CHNL->TZDCSEL_b.DCBEVT2 = 4;         ///< DCBL = high, DCBH = don't care
  PWM_PFC_CHNL->DCBCTL_b.EVT2FRCSYNCSEL = 1;   ///< ASYNC
//  PWM_PFC_CHNL->TZSEL_b.DCBEVT2 = 1;           ///< Enable DCBEVT2 as CBC source
  PWM_PFC_CHNL->TZCTL_b.DCBEVT2 = 2;           // Force low state
  PWM_PFC_CHNL->TZCLR = 0xffff;
  ACCESS_DISABLE;

  /* PWM SOC CONFIG */
  PWM_PFC_CHNL->ETSEL = (SOCASEL_PRD_EQ + SOCASEL_ENABLE);
  PWM_PFC_CHNL->ETPS = SOCAPRD_TWO_EVENT;      ///< Generate the SOCA pulse on the second event
}

/**
  * @brief  DCFAN PWM Initialization.
  */
void FanPwmInit(struct PWMGEN pwm)
{
  PWM_FAN_CHNL0->TBPRD = pwm.PeriodMax;
  PWM_FAN_CHNL1->TBPRD = pwm.PeriodMax;
  PWM_FAN_CHNL2->TBPRD = pwm.PeriodMax;

  /* Init Timer-Base Control Register */
  PWM_FAN_CHNL0->TBCTL = (TIMER_CNT_UP + CNTLD_ENABLE + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);
  PWM_FAN_CHNL1->TBCTL = (TIMER_CNT_UP + CNTLD_ENABLE + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);
  PWM_FAN_CHNL2->TBCTL = (TIMER_CNT_UP + CNTLD_ENABLE + PRDLD_IMMEDIATE + HSPCLKDIV_PRESCALE_X_1);

  /* Init Compare Control Register */
  PWM_FAN_CHNL0->CMPCTL = (LOADAMODE_PRD + LOADBMODE_PRD);
  PWM_FAN_CHNL1->CMPCTL = (LOADAMODE_PRD + LOADBMODE_PRD);
  PWM_FAN_CHNL2->CMPCTL = (LOADAMODE_PRD + LOADBMODE_PRD);

  /* Init Action Qualifier Output A Register */
  #if (HW_VERSION == HW_VERSION_20180108)
    PWM_FAN_CHNL0->AQCTLA = (CAU_CLEAR + CBU_SET);
    PWM_FAN_CHNL1->AQCTLA = (CAU_CLEAR + CBU_SET);
    PWM_FAN_CHNL2->AQCTLA = (CAU_CLEAR + CBU_SET);
  #else
    PWM_FAN_CHNL0->AQCTLA = (CAU_SET + CBU_CLEAR);
    PWM_FAN_CHNL1->AQCTLA = (CAU_SET + CBU_CLEAR);
    PWM_FAN_CHNL2->AQCTLA = (CAU_SET + CBU_CLEAR);
  #endif
  PWM_FAN_CHNL0->AQCTLB = (CAU_CLEAR + CBU_CLEAR);    // PWM DISABLE MODE NEEDED
  PWM_FAN_CHNL1->AQCTLB = (CAU_CLEAR + CBU_CLEAR);    // PWM DISABLE MODE NEEDED
  PWM_FAN_CHNL2->AQCTLB = (CAU_CLEAR + CBU_CLEAR);    // PWM DISABLE MODE NEEDED

  /* Init Dead-Band Generator Control Register for EPWM1-EPWM3 */
  PWM_FAN_CHNL0->DBCTL = 0x33;//(BP_ENABLE + POLSEL_ACTIVE_HI + PWMB_IN);//
  PWM_FAN_CHNL1->DBCTL = 0x33;//(BP_ENABLE + POLSEL_ACTIVE_HI + PWMB_IN);//
  PWM_FAN_CHNL2->DBCTL = 0x33;//(BP_ENABLE + POLSEL_ACTIVE_HI + PWMB_IN);//

  /* Init Dead-Band Generator for EPWM1-EPWM3 */
  PWM_FAN_CHNL0->DBFED = pwm.Deadband;
  PWM_FAN_CHNL1->DBFED = pwm.Deadband;
  PWM_FAN_CHNL2->DBFED = pwm.Deadband;
  PWM_FAN_CHNL0->DBRED = pwm.Deadband;
  PWM_FAN_CHNL1->DBRED = pwm.Deadband;
  PWM_FAN_CHNL2->DBRED = pwm.Deadband;

  /* Init Trip Zone */
  ACCESS_ENABLE;
  PWM_FAN_CHNL0->TZSEL = ENABLE_TZ0_OST + ENABLE_TZ5_OST + ENABLE_TZ4_OST;
  PWM_FAN_CHNL1->TZSEL = ENABLE_TZ0_OST + ENABLE_TZ5_OST + ENABLE_TZ4_OST;
  PWM_FAN_CHNL2->TZSEL = ENABLE_TZ0_OST + ENABLE_TZ5_OST + ENABLE_TZ4_OST;
  ACCESS_DISABLE;

  ACCESS_ENABLE;
  PWM_FAN_CHNL0->TZCTL = (TZA_FORCE_LO + TZB_FORCE_LO); ///< Force low state
  PWM_FAN_CHNL1->TZCTL = (TZA_FORCE_LO + TZB_FORCE_LO); ///< Force low state
  PWM_FAN_CHNL2->TZCTL = (TZA_FORCE_LO + TZB_FORCE_LO); ///< Force low state
  ACCESS_DISABLE;

  /* Init SOC Trigger Registers */
  if(g_sFanDrvParam.u8SingleShuntEn){
    PWM_FAN_CHNL0->ETSEL = (SOCASEL_CMPA_EQ_UC + SOCASEL_ENABLE); ///< Generate an SOCA pulse on TBCTR = CMPA
                                                                  ///< when the timer is incrementing
  }else{
    PWM_FAN_CHNL0->ETSEL = (SOCASEL_PRD_EQ + SOCASEL_ENABLE);     ///< Generate an SOCA pulse on TBCTR = PRD
    PWM_FAN_CHNL1->ETSEL = (SOCASEL_PRD_EQ + SOCASEL_ENABLE);
  }
  PWM_FAN_CHNL0->ETPS = SOCAPRD_THREE_EVENT;     ///< Generate an SOCA pulse on second event
  PWM_FAN_CHNL1->ETPS = SOCAPRD_THREE_EVENT;     ///< Generate an SOCA pulse on second event

  /* Init Interrupt Registers */
  PWM_FAN_CHNL0->ETSEL_b.INTEN = 1;              ///< Enable PWM Interrupt
  PWM_FAN_CHNL0->ETSEL_b.INTESEL = 2;            ///< Generate an Interrupt when TBCTR = TBPRD
  PWM_FAN_CHNL0->ETPS_b.INTPRD = 3;              ///< Generate an interrupt on third event
}

void PwmInit4SocDelay(void)
{
  PWM_SOC_DLY_CHNL->TBCTL  = PWM_FAN_CHNL0->TBCTL;
  PWM_SOC_DLY_CHNL->CMPCTL = PWM_FAN_CHNL0->CMPCTL;
  PWM_SOC_DLY_CHNL->TBPRD  = PWM_FAN_CHNL0->TBPRD;

  PWM_SOC_DLY_CHNL->CMPA = 0;
  PWM_SOC_DLY_CHNL->CMPB = 0;

  PWM_SOC_DLY_CHNL->ETSEL_b.SOCASEL = 4;    // CPMA upcount
  PWM_SOC_DLY_CHNL->ETSEL_b.SOCAEN = 1;
  PWM_SOC_DLY_CHNL->ETPS_b.SOCAPRD = 3;

  PWM_SOC_DLY_CHNL->ETSEL_b.SOCBSEL = 6;    // CMPB upcount
  PWM_SOC_DLY_CHNL->ETSEL_b.SOCBEN = 1;
  PWM_SOC_DLY_CHNL->ETPS_b.SOCBPRD = 3;
}


/**
  \brief   Config CAP0 in APWM mode.
  \param [in]    period  period value of APWM.
 */
void CapInit(uint32_t period)
{
  ECAP0->ECCTL2_b.APWM = 1;
  ECAP0->ECCTL2_b.SYNCI_EN = 1;

  ECAP0->CAP3 = period;
  ECAP0->CAP4 = (period*3)>>2;

  ECAP0->ECCLR_b.CTR_CMP = 1;
  ECAP0->ECEINT_b.CTR_CMP = 1;

  ECAP0->ECCTL2_b.TSCTRSTOP = 1;
}

/**
  * @brief  PWM Initialization.
  */
void BSP_PwmInit(void)
{
  g_sPmsmPwm.PeriodMax = SystemMtClock / g_sPmsmDrvParam.u16PwmFreq;
  g_sPmsmPwm.HalfPerMax = g_sPmsmPwm.PeriodMax / 2;
  g_sPmsmPwm.Deadband = g_sPmsmDrvParam.fPwmDtUS * SystemMtClock / 1000000;
  PmsmPwmInit(g_sPmsmPwm);

  g_sPfcPwm.PeriodMax = SystemMtClock / g_sPfcDrvParam.u16PfcPwmFreq / 2;
  g_sPfcPwm.HalfPerMax = g_sPfcPwm.PeriodMax / 2;
  PfcPwmInit(g_sPfcPwm);

  g_sFanPwm.PeriodMax  = SystemMtClock / g_sFanDrvParam.u16PwmFreq;
  g_sFanPwm.HalfPerMax = g_sFanPwm.PeriodMax / 2;
  g_sFanPwm.Deadband   = g_sFanDrvParam.fPwmDtUS * SystemMtClock / 1000000;
  FanPwmInit(g_sFanPwm);

  if(g_sFanDrvParam.u8SingleShuntEn){
    PwmInit4SocDelay();
  }

  CapInit(g_sPmsmPwm.PeriodMax);

  START_ALL_PWM;

  PWM0->TBCTL_b.SWFSYNC = 1;
}

/*---------------------------------- End of the file ---------------------------------*/
